/*--------------------------------------------------------------------------------------------------
Yatak Operation System Project Copyright 2012-2013
Author : Ilya Churaev
Started : 4 Sep 2012		Updated : 17 Mar 2013
File Name : scheduler.c		Purpose : Scheduler for tasks
--------------------------------------------------------------------------------------------------*/
#include <yatak/debug.h>
#include <yatak/yatak.h>
#include <yatak/mutex.h>
#include <sched.h>
#include <types.h>

//#define DEBUG_SCHEDULER

#ifndef DEBUG_SCHEDULER
#define dprintf
#define DBGPRINTF(s)
#endif

extern volatile task_t *current_task;
extern volatile task_t *ready_queue;

extern page_directory_t *current_directory;

bool was_switch_task = false;

task_t * GetNext ()
{
	task_t * current;
	if (current_task == NULL)
	{
		dprintf ("[GetNext] Error!!! Cannot find current tast...\n");
		return NULL;
	}
	current = (task_t *) current_task;

	if (current->child) current = current->child;
	while (current->child && current->state == TASK_STOPPED) current = current->child;
	if (current != current_task && current->state != TASK_STOPPED)
		return current;
	
	if (current->brother) current = current->brother;
	while (current->brother && current->state == TASK_STOPPED) current = current->brother;
	if (current != current_task && current->state != TASK_STOPPED)
		return current;
	while (current->parent)
	{
		current = current->parent;
		if (current->brother)
		{
			current = current->brother;
			while (current->brother && current->state == TASK_STOPPED) current = current->brother;
			if (current != current_task && current->state != TASK_STOPPED)
				return current;
		}
	}	
	return current;
}

void schedule()
{
	static int count = 0;
	static mutex_t mutex;
	//int flags;
	static bool will_switch = false;
	if (!current_task)
		return;
	
	//save_flags (flags);
	mutex_enter (&mutex);
	
	if(count > 0)
	{
		if (!will_switch && was_switch_task)
		{
			switch(current_task->cur_thread->prio)
			{
				case PRIO_DEAD:
					count = 0;
					break;
				case PRIO_IDLE:
					count = 1;
					break;
				case PRIO_LOW:
					count = 5;
					break;
				case PRIO_NORMAL:
					count = 10;
					break;
				case PRIO_HIGH:
					count = 15;
					break;
				default:
					count = 10;
					break;
			}
		}
		will_switch = false;
		was_switch_task = false;
		count--;
		mutex_leave (&mutex);
		//restore_flags(flags);
		return;
	}
	
	switch(current_task->cur_thread->prio)
	{
		case PRIO_DEAD:
			count = 0;
			break;
		case PRIO_IDLE:
			count = 1;
			break;
		case PRIO_LOW:
			count = 5;
			break;
		case PRIO_NORMAL:
			count = 10;
			break;
		case PRIO_HIGH:
			count = 15;
			break;
		default:
			count = 10;
			break;
	}
	will_switch = true;
	mutex_leave (&mutex);
	//restore_flags(flags);
	switch_task();
}
